use crate::{CameraPacket, CustomError, VideoPlayer};
use ffmpeg_sys_next::avdevice_register_all;
use sdl2::Sdl;
use std::sync::{
    atomic::{AtomicBool, Ordering},
    Arc,
};
use tokio::sync::{broadcast, Mutex};

pub struct CameraFifo {
    pub camera_in_packet_sender: broadcast::Sender<CameraPacket>,
    pub camera_player_packet_receiver: Arc<Mutex<broadcast::Receiver<CameraPacket>>>,
    pub camera_file_packet_receiver: Arc<Mutex<broadcast::Receiver<CameraPacket>>>,
}

impl CameraFifo {
    pub fn new() -> Self {
        let (camera_in_packet_sender, camera_player_packet_receiver): (
            broadcast::Sender<CameraPacket>,
            broadcast::Receiver<CameraPacket>,
        ) = broadcast::channel(5 * 1024);
        let camera_file_packet_receiver = camera_in_packet_sender.subscribe();

        CameraFifo {
            camera_in_packet_sender,
            camera_player_packet_receiver: Arc::new(Mutex::new(camera_player_packet_receiver)),
            camera_file_packet_receiver: Arc::new(Mutex::new(camera_file_packet_receiver)),
        }
    }
}

pub struct MediaPlayer {
    pub video_player: VideoPlayer,
    pub sdl: Sdl,
    pub camera_fifo: CameraFifo,
}

impl MediaPlayer {
    pub fn new(video_short_name: String, video_url: String, out_video_file: String) -> Self {
        let sdl = sdl2::init().unwrap();
        let camera_fifo = CameraFifo::new();
        let running: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
        let r = running.clone();
        // 注册 Ctrl+C 信号处理器
        ctrlc::set_handler(move || {
            println!("Received Ctrl+C signal. Exiting...");
            r.store(false, Ordering::SeqCst);
        })
        .expect("Error setting Ctrl+C handler");

        let video_player =
            VideoPlayer::new(video_short_name, video_url, out_video_file, running.clone());

        MediaPlayer {
            video_player,
            sdl,
            camera_fifo,
        }
    }

    pub async fn init(&self) -> Result<(), CustomError> {
        unsafe {
            avdevice_register_all();
        }
        Ok(())
    }

    pub async fn run(&mut self) -> Result<(), CustomError> {
        self.init().await?;

        self.video_player.find_input_context().await?;
        self.video_player.alloc_format_context().await?;
        self.video_player.open_input().await?;
        self.video_player.dump_format().await?;
        self.video_player.stream_index().await?;
        self.video_player.find_decoder().await?;
        self.video_player.in_codec_alloc_context().await?;
        self.video_player.in_parameters_to_context().await?;
        self.video_player.open_avcodec().await?;
        self.video_player.sws_get_context().await?;
        self.video_player.init_sdl(self.sdl.clone()).await?;
        self.video_player.alloc_output_context().await?;
        self.video_player.avio_open().await?;
        self.video_player.new_stream().await?;
        self.video_player.get_out_codec_parameters().await?;
        self.video_player.set_out_codec_params().await?;
        self.video_player.find_encoder().await?;
        self.video_player.out_codec_alloc_context().await?;
        self.video_player.out_parameters_to_context().await?;
        self.video_player.set_out_codec_context_params().await?;
        self.video_player.codec_open().await?;
        self.video_player.out_dump_format().await?;
        self.video_player.write_header().await?;
        self.video_player
            .read_packet_thread(self.camera_fifo.camera_in_packet_sender.clone())
            .await?;
        self.video_player
            .write_data_thread(self.camera_fifo.camera_file_packet_receiver.clone())
            .await?;
        self.video_player
            .async_codec_thread(self.camera_fifo.camera_player_packet_receiver.clone())
            .await?;
        self.video_player.player(self.sdl.clone()).await?;
        self.video_player.write_trailer().await?;

        self.video_player.close().await?;

        Ok(())
    }
}
